JavaScript Module Federation Runtime Registry ã䜿çšããåçãªã¢ãžã¥ãŒã«æ€åºã«ãããã¹ã±ãŒã©ãã«ã§é©å¿æ§ã®é«ããã€ã¯ãããã³ããšã³ãã¢ãŒããã¯ãã£ãå®çŸããŸããå®è£ ãã¡ãªãããé«åºŠãªãŠãŒã¹ã±ãŒã¹ã解説ããŸãã
JavaScript Module Federation Runtime Registry: åçãªã¢ãžã¥ãŒã«æ€åº
Webpack 5 ã§å°å ¥ããã匷åãªæ©èœã§ãã Module Federation ã¯ãJavaScript ã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯ãšãããã€æ¹æ³ãç¹ã«ãã€ã¯ãããã³ããšã³ãã®åéã«é©åœããããããŸãããããã«ãããåå¥ã«æ§ç¯ããã³ãããã€ãããç°ãªãã¢ããªã±ãŒã·ã§ã³ããå®è¡æã«ã³ãŒããšæ©èœãå ±æã§ããããã«ãªããŸããéçãªã¢ãžã¥ãŒã«ãã§ãã¬ãŒã·ã§ã³æ§æã¯äžè¬çã§ãããçã®å㯠Runtime Registry ã䜿çšãã åçãªã¢ãžã¥ãŒã«æ€åº ã«ãããŸãããã®èšäºã§ã¯ãModule Federation ã® Runtime Registry ã®æŠå¿µãæ·±ãæãäžãããã®å®è£ ãã¡ãªãããããã³é«åºŠãªãŠãŒã¹ã±ãŒã¹ãæ¢ããŸãã
Runtime Registry ãšã¯ïŒ
Module Federation ã®æèã§ã¯ãRuntime Registry ã¯ãå©çšå¯èœãªãªã¢ãŒãã¢ãžã¥ãŒã«ã«é¢ããæ å ±ãæäŸããäžå€®ãã£ã¬ã¯ããªãŸãã¯ãµãŒãã¹ãšããŠæ©èœããŸããã¢ããªã±ãŒã·ã§ã³ã®æ§æå ã§ãªã¢ãŒãã¢ãžã¥ãŒã«ã®å ŽæãããŒãã³ãŒãã£ã³ã°ãã代ããã«ãå®è¡æã«ã¬ãžã¹ããªã«ã¯ãšãªãå®è¡ããŠãå¿ èŠãªã¢ãžã¥ãŒã«ãæ€åºããã³ããŒãããŸãããã®åçãªã¢ãããŒãã«ã¯ããã€ãã®å©ç¹ããããŸãã
- ççµå: ã¢ããªã±ãŒã·ã§ã³ã¯ããªã¢ãŒãã¢ãžã¥ãŒã«ã®ç¹å®ã®ããŒãžã§ã³ãŸãã¯å Žæã«ããã»ã©å¯æ¥ã«çµåãããªããªããŸãã
- ã¹ã±ãŒã©ããªãã£: æ¶è²»ã¢ããªã±ãŒã·ã§ã³ãåãããã€ããããšãªãããªã¢ãŒãã¢ãžã¥ãŒã«ã远å ãåé€ããŸãã¯æŽæ°ããããšã容æã«ãªããŸãã
- é©å¿æ§: å®è¡æã®æ¡ä»¶ã«åºã¥ããŠç°ãªãã¢ãžã¥ãŒã«ãæäŸããããšã«ãããåçãªæ©èœãã°ã«ãš A/B ãã¹ããå¯èœã«ããŸãã
- å埩å: 1 ã€ã®ãªã¢ãŒãã¢ãžã¥ãŒã«ãå©çšã§ããªãå Žåãã¬ãžã¹ããªã¯ä»£æ¿ã®å ŽæãŸãã¯ããŒãžã§ã³ãæäŸã§ããŸãã
Runtime Registry ã䜿çšããçç±
補åã«ã¿ãã°ãã·ã§ããã³ã°ã«ãŒãããŠãŒã¶ãŒã¢ã«ãŠã³ããªã©ã®ããã€ãã®ãã€ã¯ãããã³ããšã³ãã§æ§æãããå€§èŠæš¡ãª e ã³ããŒã¹ãã©ãããã©ãŒã ãèããŠã¿ãŠãã ãããåãã€ã¯ãããã³ããšã³ãã¯åå¥ã«éçºããã³ãããã€ãããŸããRuntime Registry ããªããšãåãã€ã¯ãããã³ããšã³ãã¯ãä»ã®ãã€ã¯ãããã³ããšã³ãã«ãã£ãŠäœ¿çšãããå ±æã¢ãžã¥ãŒã«ãŸãã¯ã³ã³ããŒãã³ãã®æ£ç¢ºãªå ŽæãšããŒãžã§ã³ãç¥ãå¿ èŠããããŸããããã¯å¯çµåãäœæããæŽæ°ãå°é£ã«ããŸããããšãã°ãå ±æ UI ã³ã³ããŒãã³ããæŽæ°ããã«ã¯ãããã«äŸåãããã¹ãŠã®ãã€ã¯ãããã³ããšã³ããåãããã€ããå¿ èŠããããŸãã
ããããRuntime Registry ã䜿çšãããšããã€ã¯ãããã³ããšã³ãã¯ãå¿ èŠãªã³ã³ããŒãã³ãã®å ŽæãšããŒãžã§ã³ãã¬ãžã¹ããªã«ã¯ãšãªããã ãã§æžã¿ãŸããã¬ãžã¹ããªã¯é©åãªæ å ±ãæäŸã§ãããã€ã¯ãããã³ããšã³ãã¯ã³ã³ããŒãã³ããåçã«ããŒãã§ããŸãããã®ççµåã«ãããç¬ç«ããæŽæ°ãå¯èœã«ãªããç Žå£çãªå€æŽã®ãªã¹ã¯ã軜æžãããŸãã
Runtime Registry ã®å®è£
Runtime Registry ã®å®è£ æ¹æ³ã¯ãåçŽãª JSON ãã¡ã€ã«ãããããŒãžã§ã³ç®¡çãšã«ãŒãã£ã³ã°æ©èœãåããããé«åºŠãªãµãŒãã¹ãŸã§ãããã€ããããŸããããã§ã¯ãWeb ãµãŒããŒã§ãã¹ããããŠããåçŽãª JSON ãã¡ã€ã«ã䜿çšããåºæ¬çãªäŸã瀺ããŸãã
1. ã¬ãžã¹ããªå®çŸ© (registry.json):
{
"modules": {
"@my-org/product-card": {
"1.0.0": "https://cdn.example.com/product-card/1.0.0/remoteEntry.js",
"1.1.0": "https://cdn.example.com/product-card/1.1.0/remoteEntry.js"
},
"@my-org/checkout-button": {
"2.0.0": "https://cdn.example.com/checkout-button/2.0.0/remoteEntry.js"
}
}
}
ãã® JSON ãã¡ã€ã«ã¯ãå©çšå¯èœãªã¢ãžã¥ãŒã«ãšãã®å¯Ÿå¿ãã URL ãå®çŸ©ããŸããåã¢ãžã¥ãŒã«ã«ã¯ãããããã® `remoteEntry.js` ãã¡ã€ã«ãæãããŒãžã§ã³ç®¡çããããšã³ããªããããŸããããã«ãããããŒãžã§ã³ç®¡çãšãå¿ èŠã«å¿ããç°¡åãªããŒã«ããã¯ãå¯èœã«ãªããŸãã
2. æ¶è²»ã¢ããªã±ãŒã·ã§ã³:
async function loadRemote(moduleName, version) {
const registryUrl = 'https://example.com/registry.json';
const response = await fetch(registryUrl);
const registry = await response.json();
const moduleInfo = registry.modules[moduleName];
if (!moduleInfo) {
throw new Error(`Module "${moduleName}" not found in registry.`);
}
const moduleUrl = moduleInfo[version];
if (!moduleUrl) {
throw new Error(`Version "${version}" for module "${moduleName}" not found.`);
}
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = moduleUrl;
script.type = 'text/javascript';
script.async = true;
script.onload = () => {
// Module is loaded, you can now access it using window[moduleName]
resolve(window[moduleName]);
};
script.onerror = (error) => {
console.error(`Error loading module ${moduleName} from ${moduleUrl}:`, error);
reject(error);
};
document.head.appendChild(script);
});
}
// Example usage:
loadRemote('@my-org/product-card', '1.0.0')
.then((module) => {
// Use the loaded module
const ProductCard = module.ProductCard;
const productCardInstance = new ProductCard({ name: 'Example Product' });
document.getElementById('product-card-container').appendChild(productCardInstance.render());
})
.catch((error) => {
console.error('Failed to load product card:', error);
});
ãã®ã³ãŒãã¹ããããã¯ãã¬ãžã¹ããªã®ååŸãç®çã®ã¢ãžã¥ãŒã«ãšããŒãžã§ã³ã®ç¹å®ããªã¢ãŒããšã³ããªã®åçãªããŒãæ¹æ³ã瀺ããŠããŸããåºæ¬çãªãšã©ãŒåŠçãå«ãŸããŠããŸãã
3. Webpack èšå® (ãªã¢ãŒãã¢ããªã±ãŒã·ã§ã³):
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
//...
plugins: [
new ModuleFederationPlugin({
name: '@my-org/product-card',
filename: 'remoteEntry.js',
exposes: {
'./ProductCard': './src/ProductCard',
},
// shared: { ... }, // Shared dependencies
}),
],
};
ããã¯ã`ProductCard` ã³ã³ããŒãã³ããå ¬éãããªã¢ãŒãã¢ããªã±ãŒã·ã§ã³ã®æšæºç㪠Module Federation Webpack èšå®ã§ããéèŠãªã®ã¯ã`filename` ãã¬ãžã¹ããªã§åç §ããããã¡ã€ã«ã§ãã `remoteEntry.js` ã§ããããšã§ãã
é«åºŠãªãŠãŒã¹ã±ãŒã¹
äžèšã®åçŽãªäŸã¯ãããè€éãªã·ããªãªãåŠçããããã«æ¡åŒµã§ããŸãã
ããŒãžã§ã³ç®¡ç
ã¬ãžã¹ããªã¯åã¢ãžã¥ãŒã«ã®è€æ°ã®ããŒãžã§ã³ãæ ŒçŽã§ããæ¶è²»ã¢ããªã±ãŒã·ã§ã³ã¯åžæããããŒãžã§ã³ãæå®ã§ããŸããããã¯ãäºææ§ãç¶æããæ®µéçãªã¢ããã°ã¬ãŒããå¯èœã«ããããã«éèŠã§ãã
äŸ: ã¬ãžã¹ããªã¯ããŒãžã§ã³æ å ±ãå«ãããšãã§ããæ¶è²»ã¢ããªã±ãŒã·ã§ã³ã¯ç¹å®ã®ããŒãžã§ã³ãŸãã¯ããŒãžã§ã³ã®ç¯å² (äŸ: '>=1.0.0 <2.0.0') ãèŠæ±ã§ããŸããã¬ãžã¹ããªã¯ãèŠæ±ã«åºã¥ããŠé©å㪠URL ãè¿ãããšãã§ããŸãã
ã«ãŒãã£ã³ã°ãšããŒããã©ã³ã·ã³ã°
ã¬ãžã¹ããªã¯ãå¯çšæ§ãŸãã¯å°ççäœçœ®ã«åºã¥ããŠãªã¯ãšã¹ããç°ãªããµãŒããŒã«ãªãã€ã¬ã¯ãããããŒããã©ã³ãµãŒãšããŠæ©èœã§ããŸããããã«ãããããã©ãŒãã³ã¹ãšä¿¡é Œæ§ãåäžããŸãã
äŸ: ã¬ãžã¹ããªã«ã¯ãåãã¢ãžã¥ãŒã«ã®è€æ°ã® URL ããããå URL ã¯ç°ãªã CDN ãŸãã¯ãµãŒããŒãæããŠããå¯èœæ§ããããŸããã¬ãžã¹ããªã¯ãããŒããã©ã³ã·ã³ã°ã¢ã«ãŽãªãºã ã䜿çšããŠãå©çšå¯èœãªãµãŒããŒå šäœã«ãªã¯ãšã¹ãã忣ã§ããŸãã
èªèšŒãšèªå¯
ã¬ãžã¹ããªã¯ãèªèšŒããã³èªå¯ããªã·ãŒã匷å¶ããèš±å¯ãããã¢ããªã±ãŒã·ã§ã³ã®ã¿ãç¹å®ã®ã¢ãžã¥ãŒã«ã«ã¢ã¯ã»ã¹ã§ããããšãä¿èšŒã§ããŸããããã¯ãæ©å¯æ§ã®é«ãã³ãŒããšããŒã¿ãä¿è·ããããã«äžå¯æ¬ ã§ãã
äŸ: ã¬ãžã¹ããªã¯ãã¢ãžã¥ãŒã«æ å ±ã«ã¢ã¯ã»ã¹ããããã« API ããŒãŸãã¯ããŒã¯ã³ãèŠæ±ããå ŽåããããŸããæ¶è²»ã¢ããªã±ãŒã·ã§ã³ã¯ãã¢ãžã¥ãŒã« URL ãååŸããããã«æ£ããè³æ Œæ å ±ãæäŸããå¿ èŠããããŸãã
æ©èœãã°ã«
ã¬ãžã¹ããªã¯ãã¢ããªã±ãŒã·ã§ã³ãåãããã€ããããšãªããæ©èœãåçã«æå¹ãŸãã¯ç¡å¹ã«ã§ããæ©èœãã°ã«ãå®è£ ããããã«äœ¿çšã§ããŸããããã¯ãA/B ãã¹ããæ°æ©èœã®æ®µéçãªããŒã«ã¢ãŠãã«åœ¹ç«ã¡ãŸãã
äŸ: ã¬ãžã¹ããªã¯ãç°ãªãç°å¢ãŸãã¯ãŠãŒã¶ãŒã°ã«ãŒãã«å¯ŸããŠç°ãªãæ§æãæã€å ŽåããããŸãããŠãŒã¶ãŒã® ID ãŸãã¯ç°å¢ã«åºã¥ããŠãã¬ãžã¹ããªã¯åãã¢ãžã¥ãŒã«ã«å¯ŸããŠç°ãªã URL ãè¿ãã广çã«ç¹å®ã®æ©èœãæå¹ãŸãã¯ç¡å¹ã«ããŸãã
åçãªã¢ãžã¥ãŒã«åæ
ã¬ãžã¹ããªã¯ãå®è¡æã«ããŒããããã¢ãžã¥ãŒã«ãå®è¡æã®æ¡ä»¶ãŸãã¯ãŠãŒã¶ãŒã®æäœã«äŸåããåçãªã¢ãžã¥ãŒã«åæãä¿é²ã§ããŸããããã«ãããé«åºŠã«é©å¿å¯èœã§ããŒãœãã©ã€ãºãããã¢ããªã±ãŒã·ã§ã³ãå¯èœã«ãªããŸãã
äŸ: ãŠãŒã¶ãŒã®å¥œã¿ãŸãã¯çŸåšã®ããŒãžã®ã³ã³ããã¹ãã«åºã¥ããŠãã¢ããªã±ãŒã·ã§ã³ã¯é©åãªã¢ãžã¥ãŒã«ãããŒãããããã«ã¬ãžã¹ããªã«ã¯ãšãªã§ããŸããããã«ãããé«åºŠã«ã«ã¹ã¿ãã€ãºããããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãå¯èœã«ãªããŸãã
èæ ®äºé ãšãã¹ããã©ã¯ãã£ã¹
Runtime Registry ã¯å€ãã®ã¡ãªãããæäŸããŸãããæ¬¡ã®èŠå ãèæ ®ããããšãäžå¯æ¬ ã§ãã
- ããã©ãŒãã³ã¹: ã¬ãžã¹ããªæ å ±ã®ååŸã«ã¯è¿œå ã®ãããã¯ãŒã¯ãªã¯ãšã¹ããçºçããŸããã¬ã€ãã³ã·ãæå°éã«æããããã«ãã¬ãžã¹ããªããŒã¿ããã£ãã·ã¥ããããšãæ€èšããŠãã ããã
- è€éã: Runtime Registry ã®å®è£ ãšä¿å®ã¯ãã¢ãŒããã¯ãã£ã«è€éãã远å ããŸãããã®ã¢ãããŒããæ¡çšããåã«ããã¬ãŒããªããæ éã«è©äŸ¡ããŠãã ããã
- ã»ãã¥ãªãã£: ã¬ãžã¹ããªãäžæ£ã¢ã¯ã»ã¹ãæ¹ããããä¿è·ããŠãã ãããé©åãªèªèšŒããã³èªå¯ã¡ã«ããºã ãå®è£ ããŠãã ããã
- ãšã©ãŒåŠç: ã¬ãžã¹ããªãå©çšã§ããªãå Žåãã¢ãžã¥ãŒã«ãããŒãã§ããªãå Žåã«å¯ŸåŠããããã«ãå ç¢ãªãšã©ãŒåŠçãå®è£ ããŠãã ããã
- ã¹ã±ãŒã©ããªãã£: ã¬ãžã¹ããªãäºæ³ãããè² è·ãåŠçã§ããã¢ããªã±ãŒã·ã§ã³ã®æé·ã«åãããŠã¹ã±ãŒãªã³ã°ã§ããããšã確èªããŠãã ãããããã©ãŒãã³ã¹ãåäžãããããã«ã忣ããŒã¿ããŒã¹ãŸãã¯ãã£ãã·ã¥ã¬ã€ã€ãŒã®äœ¿çšãæ€èšããŠãã ããã
- éäžç®¡ç: äžè²«æ§ã確ä¿ããç«¶åãåé¿ããããã«ãã¬ãžã¹ããªã®ã¬ããã³ã¹ãšå€æŽç®¡çããã»ã¹ãé©åã«å®è£ ããŠãã ããã
- ç£èŠ: ããã©ãŒãã³ã¹ãšå¯çšæ§ãç£èŠããŠãåé¡ã proactively ã«ç¹å®ããã³è§£æ±ºããŠãã ããã
åçŽãª JSON ã¬ãžã¹ããªã®ä»£æ¿ææ®µ
åçŽãª JSON ãã¡ã€ã«ã¯è¯ãåºçºç¹ãšããŠæ©èœããŸãããæ¬çªç°å¢ã§ã¯ããå ç¢ãªãœãªã¥ãŒã·ã§ã³ãå¿ èŠã«ãªãããšããããããŸãããããã®ä»£æ¿ææ®µãæ€èšããŠãã ããã
- ã«ã¹ã¿ã API ãµãŒãã¹: Node.jsãPythonããŸã㯠Go ã§æ§ç¯ãããå°çš API ãµãŒãã¹ã¯ãã¬ãžã¹ããªããžãã¯ã«å¯Ÿããããæè»æ§ãšå¶åŸ¡ãæäŸããŸããããã«ãããèªèšŒãèªå¯ãããŒãžã§ã³ç®¡çãããŒããã©ã³ã·ã³ã°ãªã©ã®æ©èœãå¯èœã«ãªããŸãã
- ãµãŒãã¹æ€åºããŒã« (äŸ: Consul, etcd, ZooKeeper): ãããã®ããŒã«ã¯ããµãŒãã¹æ§æã®ç®¡çãšåçãªãµãŒãã¹æ€åºã®æäŸãç®çãšããŠããŸãããããã䜿çšããŠãã¢ãžã¥ãŒã«ãã§ãã¬ãŒã·ã§ã³ã¬ãžã¹ããªããŒã¿ãä¿åããã³ç®¡çã§ããŸãã
- ã¯ã©ãŠãããŒã¹ã®æ§æãµãŒãã¹ (äŸ: AWS AppConfig, Azure App Configuration, Google Cloud Config): ãããã®ãµãŒãã¹ã¯ãã¢ãžã¥ãŒã«ãã§ãã¬ãŒã·ã§ã³ã¬ãžã¹ããªãå«ãã¢ããªã±ãŒã·ã§ã³æ§æãäžå çãã€ã¹ã±ãŒã©ãã«ã«ç®¡çããæ¹æ³ãæäŸããŸãã
- æ¢åã®ãã€ã¯ããµãŒãã¹ãªãŒã±ã¹ãã¬ãŒã·ã§ã³ãã©ãããã©ãŒã (äŸ: Kubernetes): æ¢ã«ãã€ã¯ããµãŒãã¹ãªãŒã±ã¹ãã¬ãŒã·ã§ã³ãã©ãããã©ãŒã ã䜿çšããŠããå Žåã¯ãã¢ãžã¥ãŒã«ãã§ãã¬ãŒã·ã§ã³ã¬ãžã¹ããªã®çµã¿èŸŒã¿ãµãŒãã¹æ€åºããã³æ§æç®¡çæ©èœãå©çšã§ããŸãã
äŸ: ã°ããŒãã« e ã³ããŒã¹ãã©ãããã©ãŒã
è€æ°ã®åœã«ã¹ãã¢ããã³ããæã€ã°ããŒãã« e ã³ããŒã¹ãã©ãããã©ãŒã ãæ³åããŠãã ãããååœã«ã¯ãç°ãªã補åã«ã¿ãã°ãæ¯æãæ¹æ³ãé éãªãã·ã§ã³ãããå ŽåããããŸããRuntime Registry ã¯ããŠãŒã¶ãŒã®å Žæãšå¥œã¿ã«åºã¥ããŠé©åãªã¢ãžã¥ãŒã«ãåçã«ããŒãããããã«äœ¿çšã§ããŸãã
ããšãã°ããã€ãã®ãŠãŒã¶ãŒã¯ããã€ãèªã®èª¬æãšãŠãŒã建ãŠã®äŸ¡æ Œã®è£œåã«ã¿ãã°ã衚瀺ããå ŽåããããŸãããæ¥æ¬ã®ãŠãŒã¶ãŒã¯ãæ¥æ¬èªã®èª¬æãšå建ãŠã®äŸ¡æ Œã®è£œåã«ã¿ãã°ã衚瀺ããå ŽåããããŸããRuntime Registry ã¯ããŠãŒã¶ãŒã®å Žæãšå¥œã¿ã«åºã¥ããŠããŒãããã¢ãžã¥ãŒã«ã決å®ããŸãã
ããã«ããŠãŒã¶ãŒã®å Žæã«åºã¥ããŠæ¯æãã¢ãžã¥ãŒã«ãåçã«éžæã§ããŸãããã€ãã®ãŠãŒã¶ãŒã¯ PayPal ãŸãã¯ã¯ã¬ãžããã«ãŒãã§ã®æ¯æããªãã·ã§ã³ã衚瀺ããå ŽåããããŸãããæ¥æ¬ã®ãŠãŒã¶ãŒã¯ã¯ã¬ãžããã«ãŒããŸãã¯ã³ã³ããæããªãã·ã§ã³ã衚瀺ããå ŽåããããŸãã
ãã®ã¬ãã«ã®åçãªã«ã¹ã¿ãã€ãºã¯ãRuntime Registry ãªãã§ã¯éæãå°é£ã§ãã
çµè«
Runtime Registry ã¯ãJavaScript Module Federation ã§åçãªã¢ãžã¥ãŒã«æ€åºãå¯èœã«ãã匷åãªããŒã«ã§ããççµåãã¹ã±ãŒã©ããªãã£ãé©å¿æ§ãå埩åãªã©ãããã€ãã®ã¡ãªãããæäŸããŸããRuntime Registry ã®å®è£ ã¯ã¢ãŒããã¯ãã£ã«è€éãã远å ããŸãããç¹ã«å€§èŠæš¡ã§è€éãªã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã¡ãªãããã³ã¹ããäžåãããšããããããŸãããã®èšäºã§æŠèª¬ãããŠããèŠå ãæ éã«èæ ®ããããšã§ãRuntime Registry ãæ£åžžã«å®è£ ããModule Federation ã®å¯èœæ§ãæå€§éã«åŒãåºãããšãã§ããŸãã
ãã€ã¯ãããã³ããšã³ãã¢ãŒããã¯ãã£ãé²åãç¶ããã«ã€ããŠãRuntime Registry ã¯ãã¹ã±ãŒã©ãã«ã§é©å¿æ§ã®é«ã Web ã¢ããªã±ãŒã·ã§ã³ãå¯èœã«ããäžã§ãŸããŸãéèŠãªåœ¹å²ãæãããŸãããã®ãã¯ãããžãŒãæ¡çšããããã³ããšã³ãéçºã®æªæ¥ãæ§ç¯ããŠãã ããã